package com.evolved.automata.examples.sudoku;
import com.evolved.automata.*;
import java.util.*;

public class BoardUtilities {
	// This reference actually stores a LinkedList<Integer>
	private LinkedList[][] j_Board;
	
	public BoardUtilities(LinkedList[][] board)
	{
		j_Board=board;
	}
	
	/*
	 * This function only returns the value of a SudokuBoard Cell if there is only one possibility.
	 * Otherwise returns null
	 * 
	 */
	public Integer GetDefiniteValue(int row, int column)
	{
		if ((j_Board[row][column]!=null)&&(j_Board[row][column].size()==1))
			return (Integer)j_Board[row][column].get(0);
		else
			return null;
	}
	
	public LinkedList<IntPair> GetSuperCellSiblings(int row, int column)
	{
		int baseRowOffset=3*(row / 3);
		int baseColOffset=3*(column / 3);
		LinkedList<IntPair> siblingCells = new LinkedList<IntPair>();
		int boardRow, boardCol;
		for (int i=0;i<3;i++)
		{
			for (int j=0;j<3;j++)
			{
				boardRow=baseRowOffset+i;
				boardCol=baseColOffset+j;
				if ((boardRow==row)&&(boardCol==column))
					continue;
				siblingCells.add(new IntPair(boardRow,boardCol));
				
			}
		}
		return siblingCells;
	}
	
	public LinkedList<IntPair> GetColumnSiblings(int row,int column)
	{
		LinkedList<IntPair> siblingCells = new LinkedList<IntPair>();
		for (int i=0;i<9;i++)
		{
			if (i!=row)
				siblingCells.add(new IntPair(i,column));
		}
		return siblingCells;
	}
	
	public LinkedList<IntPair> GetRowSiblings(int row, int column)
	{
		LinkedList<IntPair> siblingCells = new LinkedList<IntPair>();
		for (int j=0;j<9;j++)
		{
			if (j!=column)
				siblingCells.add(new IntPair(row,j));
		}
		return siblingCells;
	}
	
	
	
	
	/*
	 * Returns the sibling values of a cell that only 
	 * Preconditions:
	 * row is within 0 and 8
	 * column is within 0 and 8
	 * 
	 * Post-conditions:
	 * siblingValues is either empty or contains the Integer values excluded from row and column 
	 * IMPROVEMENT NOTE: this can be refactored to use the method GetSuperCellSiblings
	 */
	private LinkedList<Integer> GetExcludedValuesFromSuperCellSiblings(int row, int column)
	{
		int baseRowOffset=3*(row / 3);
		int baseColOffset=3*(column / 3);
		LinkedList<Integer> siblingValues = new LinkedList<Integer>();
		Integer cellValue;
		int boardRow, boardCol;
		for (int i=0;i<3;i++)
		{
			for (int j=0;j<3;j++)
			{

				boardRow=baseRowOffset+i;
				boardCol=baseColOffset+j;
				if ((boardRow==row)&&(boardCol==column))
					continue;
				cellValue=GetDefiniteValue(boardRow,boardCol);
				if (cellValue!=null)
					siblingValues.add(cellValue);
				
			}
		}
		return siblingValues;
	}
	

	
	
	private LinkedList<Integer> GetExcludedValuesFromRow(int row, int column)
	{
		LinkedList<Integer> rowExcludedValues = new LinkedList<Integer>();
		Integer definiteValue;
		for (int j=0;j<9;j++)
		{
			definiteValue=GetDefiniteValue(row, j);
			if ((definiteValue!=null)&&(column!=j))
				rowExcludedValues.add(definiteValue);
		}
		return rowExcludedValues;
	}
	
	private LinkedList<Integer> GetExcludedValuesFromColumn(int row, int column)
	{
		LinkedList<Integer> colExcludedValues = new LinkedList<Integer>();
		Integer definiteValue;
		for (int i=0;i<9;i++)
		{
			definiteValue=GetDefiniteValue(i, column);
			if (definiteValue!=null)
				colExcludedValues.add(definiteValue);
		}
		return colExcludedValues;
	}
	
	/*
	 * This is the key method that determines the possible actions from a cell
	 * If there are no possible values then return value is empty List
	 */
	public LinkedList<Integer> GetChoices(int row, int column)
	{
		
		boolean[] excludedValues = new boolean[9];
		for (Integer excludedValue:GetExcludedValuesFromColumn(row, column))
		{
			excludedValues[excludedValue.intValue()]=true;
		}
		
		for (Integer excludedValue:GetExcludedValuesFromRow(row, column))
		{
			excludedValues[excludedValue.intValue()]=true;
		}
		
		for (Integer excludedValue:GetExcludedValuesFromSuperCellSiblings(row,column))
		{
			excludedValues[excludedValue.intValue()]=true;
		}
		
		LinkedList<Integer> finalChoices = new LinkedList<Integer>();
		for (int index=0;index<9;index++)
		{
			if (!excludedValues[index])
				finalChoices.add(new Integer(index));
		}
		if (finalChoices.size()==0)
			System.out.println("Assert failure");
		return finalChoices;
	}
}
